/****************************************************************************
 * Copyright (c) 2008, 2010 Andreas Unger and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Andreas Unger - initial API and implementation 
 ****************************************************************************/

package org.eclipselabs.damos.dml.services;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipselabs.damos.dml.DMLPlugin;
import org.eclipselabs.damos.dml.internal.services.BlockGroupDescriptorImpl;

/**
 * @author Andreas Unger
 *
 */
public class BlockGroupService {

	private static final String EXTENSION_POINT_NAME = "blockGroups";
	private static final String LISTENER_ELEMENT = "group";
	private static final String ID_ATTRIBUTE = "id";
	private static final String NAME_ATTRIBUTE = "name";
	private static final String SUPERGROUP_ATTRIBUTE = "supergroup";

	private static BlockGroupService instance;
	private Map<String, BlockGroupDescriptor> groups;
	
	/**
	 * 
	 */
	private BlockGroupService() {
	}
	
	public static BlockGroupService getInstance() {
		if (instance == null) {
			instance = new BlockGroupService();
		}
		return instance;
	}
	
	public Collection<BlockGroupDescriptor> getBlockGroupDescriptors() {
		if (groups == null) {
			loadBlockGroups();
		}
		return groups.values();
	}
	
	public BlockGroupDescriptor getBlockGroupDescriptor(String id) {
		if (groups == null) {
			loadBlockGroups();
		}
		return groups.get(id);
	}
	
	private void loadBlockGroups() {
		groups = new HashMap<String, BlockGroupDescriptor>();
		List<SupergroupMapping> supergroupMappings = new ArrayList<SupergroupMapping>();

		IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
				DMLPlugin.PLUGIN_ID, EXTENSION_POINT_NAME);

		for (IExtension extension : extensionPoint.getExtensions()) {
			for (IConfigurationElement configurationElement : extension.getConfigurationElements()) {
				if (LISTENER_ELEMENT.equals(configurationElement.getName())) {
					try {
						String id = getRequiredAttribute(configurationElement, ID_ATTRIBUTE);
						String name = getRequiredAttribute(configurationElement, NAME_ATTRIBUTE);
						String supergroupId = configurationElement.getAttribute(SUPERGROUP_ATTRIBUTE);

						BlockGroupDescriptorImpl group = new BlockGroupDescriptorImpl();
						group.setId(id);
						group.setName(name);
						groups.put(id, group);
						if (supergroupId != null && supergroupId.length() > 0) {
							SupergroupMapping supergroupMapping = new SupergroupMapping();
							supergroupMapping.group = group;
							supergroupMapping.supergroupId = supergroupId;
							supergroupMapping.contributorExtension = extension;
							supergroupMappings.add(supergroupMapping);
						}
					} catch (Exception e) {
						logError(e, extensionPoint, extension);
					}
				}
			}
		}
		
		for (SupergroupMapping supergroupMapping : supergroupMappings) {
			try {
				BlockGroupDescriptor supergroup = groups.get(supergroupMapping.supergroupId);
				if (supergroup == null) {
					throw new IllegalArgumentException("Supergroup '" + supergroupMapping.supergroupId + "' not found");
				}
				supergroupMapping.group.setSupergroup(supergroup);
			} catch (Exception e) {
				logError(e, extensionPoint, supergroupMapping.contributorExtension);
			}
		}
	}
	
	private void logError(Exception e, IExtensionPoint extensionPoint, IExtension extension) {
		DMLPlugin.INSTANCE.getPluginLogger().log(
				new Status(IStatus.ERROR, DMLPlugin.PLUGIN_ID,
						"Failed to load block group in plug-in '"
						+ extension.getContributor().getName()
						+ "' in extension of '"
						+ extensionPoint.getUniqueIdentifier()
						+ "'", e));
	}
	
	private String getRequiredAttribute(IConfigurationElement configurationElement, String name) {
		String value = configurationElement.getAttribute(name);
		if (value == null) {
			throw new IllegalArgumentException("Missing '" + name + "' attribute");
		}
		return value;
	}
	
	private static class SupergroupMapping {
		
		public BlockGroupDescriptorImpl group;
		public String supergroupId;
		public IExtension contributorExtension;
		
	}

}
